package com.yonyou.crm.sys.login.ctrl;

import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springside.modules.security.utils.Digests;
import org.springside.modules.utils.Encodes;

import com.yonyou.crm.common.enumeration.entity.EnableStateEnum;
import com.yonyou.crm.common.exception.CrmMessageException;
import com.yonyou.crm.common.login.context.LoginContextConstant;
import com.yonyou.crm.common.rest.constant.PCCodeConstant;
import com.yonyou.crm.common.rest.util.RequestUtil;
import com.yonyou.crm.common.rest.util.ResponseUtil;
import com.yonyou.crm.sys.log.entity.SysLogVO;
import com.yonyou.crm.sys.log.rmitf.ISysLogRmService;
import com.yonyou.crm.sys.login.rmitf.ILoginRmService;
import com.yonyou.crm.sys.user.entity.TypeEnum;
import com.yonyou.crm.sys.user.entity.UserVO;
import com.yonyou.iuap.auth.shiro.AuthConstants;
import com.yonyou.iuap.auth.token.ITokenProcessor;
import com.yonyou.iuap.auth.token.TokenFactory;
import com.yonyou.iuap.auth.token.TokenParameter;
import com.yonyou.iuap.utils.CookieUtil;


@RestController
@Scope("prototype")
public class PcLoginCtrl {

	public static final int HASH_INTERATIONS = 1024;

	@Autowired
	private ILoginRmService service;

	// 为网页版本的登录Controller指定webTokenProcessor 相应的移动的指定为maTokenProcessor
	@Autowired()
	protected ITokenProcessor webTokenProcessor;

	@Autowired
	private TokenFactory tokenFactory;
	
	@Autowired
	protected ISysLogRmService LogService;

	
	/**
	 * 登录操作
	 * @param request
	 * @param response
	 * @return
	 * @throws CrmMessageException
	 */
	@RequestMapping(value = "login", method = RequestMethod.POST)
	public Object formLogin(HttpServletRequest request, HttpServletResponse response)
			throws CrmMessageException {

		JSONObject paramObj = RequestUtil.getParamObject(request);

		String userName = (String) paramObj.get("username");
		String passWord = (String) paramObj.get("password");

		if (StringUtils.isBlank(userName) || StringUtils.isBlank(passWord)) {
			throw new CrmMessageException(PCCodeConstant.ServiceFormVaild, "用户名或密码不能为空！");
		}
		
		UserVO user = service.login(userName);
		
		if (user == null) {
			throw new CrmMessageException(PCCodeConstant.ServiceFormVaild, "用户不存在！");
		}
		
		if (user.getEnableState().intValue() == EnableStateEnum.DISABLE.getValue()) {
			throw new CrmMessageException(PCCodeConstant.ServiceFormVaild, "用户已停用！");
		}
		
		//非管理员验证角色
		if (!isAdmin(user.getType().intValue())) {
			
			if (user.getRoleId() == null || user.getRoleId().intValue() == 0) {
				throw new CrmMessageException(PCCodeConstant.ServiceFormVaild, "用户还未分配角色，请与联系管理员！");
			}
			
			if (isNoOrg(user)) {
				throw new CrmMessageException(PCCodeConstant.ServiceFormVaild, "用户公司或部门信息缺失，请与联系管理员！");
			}
		}

		//系统管理员不校验密码
		if (TypeEnum.XTADMIN.getValue() == user.getType() || TypeEnum.JTADMIN.getValue() == user.getType()) {
			process(request, response, userName, user);
			return ResponseUtil.getObject();
		}
		
		// 校验密码
		byte[] hashPassword = Digests.sha1(passWord.getBytes(), Encodes.decodeHex(user.getSalt()), HASH_INTERATIONS);
		String checkPwd = Encodes.encodeHex(hashPassword);
		
		if (checkPwd.equals(user.getPassword())) {
			process(request, response, userName, user);
		} else {
			throw new CrmMessageException(PCCodeConstant.ServiceFormVaild, "用户名或密码输入有误！");
		}
		return ResponseUtil.getObject();
	}

	private void process(HttpServletRequest request, HttpServletResponse response, String userName, UserVO user) throws CrmMessageException {
		TokenParameter tp = new TokenParameter();
		tp.setUserid(userName);
		// 设置登录时间
		tp.setLogints(String.valueOf(System.currentTimeMillis()));
		// 租户信息,saas应用登录的时候获取用户信息，设置租户id
		tp.getExt().put(AuthConstants.PARAM_TENANTID, user.getTenantId().toString());
		Cookie[] cookies = webTokenProcessor.getCookieFromTokenParameter(tp);
		for (Cookie cookie : cookies) {
			response.addCookie(cookie);
		}
		
        //设置用户信息
        response.addCookie(new Cookie(LoginContextConstant.UserId, user.getId().toString()));
        response.addCookie(new Cookie(LoginContextConstant.OrgId, user.getOrgId().toString()));
        if(user.getDeptId() != null) {
        	response.addCookie(new Cookie(LoginContextConstant.DeptId, user.getDeptId().toString()));        	
        }
        try {
			response.addCookie(new Cookie("name", URLEncoder.encode(user.getName(), "UTF-8")));
		} catch (UnsupportedEncodingException e) {
			throw new CrmMessageException(PCCodeConstant.ServerError, "编码转换异常");
		}
        if (user.getRoleId() != null) {
        	response.addCookie(new Cookie(LoginContextConstant.RoleId, user.getRoleId().toString()));
        }
        if (user.getRoleType() != null) {
        	response.addCookie(new Cookie(LoginContextConstant.ROLETYPE, user.getRoleType().toString()));
        }
        response.addCookie(new Cookie(LoginContextConstant.UserType, user.getType().toString()));
        
        
        // 记录登录日志
 		SysLogVO logInfo = new SysLogVO();
 		logInfo.setStatus("0");
 		logInfo.setInfo("登录成功!");
 		logInfo.setExtrainfo(getIpAddr(request));
 		logInfo.setLevel("trace");
 		logInfo.setModule("login"); // 日志模块
 		logInfo.setTenantId(user.getOrgId());
 		logInfo.setUserId(user.getId());
 		logInfo.setExtraflag("pc"); // pc端登录
 		SysLogVO reSysLogVO = LogService.insert(logInfo);
	}
	
	/**
	 * 登出操作
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "logout", method = RequestMethod.POST)
	public Object logout(HttpServletRequest request, HttpServletResponse response) {
		
		String token = CookieUtil.findCookieValue(request.getCookies(), "token");
		String userId = CookieUtil.findCookieValue(request.getCookies(), "u_usercode");
		
		if (StringUtils.isNotBlank(token)) {
			
			SecurityUtils.getSubject().logout();
			
			ITokenProcessor tokenProcessor = tokenFactory.getTokenProcessor(token);
			tokenProcessor.getLogoutCookie(token, userId);
			
			for (Cookie cookie : request.getCookies()) {
				if (!"basedir".equals(cookie.getName())) {
					cookie.setMaxAge(0);
					response.addCookie(cookie);
				}
			}
		}
		
		return ResponseUtil.getObject();
	}
	
	/** 
     * 获取当前网络ip 
     * @param request 
     * @return 
     */  
    public String getIpAddr(HttpServletRequest request){  
        String ipAddress = request.getHeader("x-forwarded-for");  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getHeader("Proxy-Client-IP");  
            }  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getHeader("WL-Proxy-Client-IP");  
            }  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getRemoteAddr();  
                if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){  
                    //根据网卡取本机配置的IP  
                    InetAddress inet=null;  
                    try {  
                        inet = InetAddress.getLocalHost();  
                    } catch (UnknownHostException e) {  
                        e.printStackTrace();  
                    }  
                    ipAddress= inet.getHostAddress();  
                }  
            }  
            //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割  
            if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15  
                if(ipAddress.indexOf(",")>0){  
                    ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));  
                }  
            }  
            return ipAddress;   
    }
    
    private boolean isAdmin(int type) {
    	return type == TypeEnum.XTADMIN.getValue() || type == TypeEnum.JTADMIN.getValue() || type == TypeEnum.GSADMIN.getValue();
    }

    private boolean isNoOrg(UserVO user) {
    	return (user.getOrgId() == null || user.getOrgId().longValue() == 0 || user.getDeptId() == null || user.getDeptId().longValue() == 0);
    }
}
